import React from 'react';
import type {FC, PropsWithChildren, MouseEvent, DragEvent, CSSProperties} from 'react';
import type { IBaseData, IComponent } from '@bastet/widgets';
import "./droppable-style.less";
import { Droppable, IDroppable, IDroppableComponent } from "./Droppable";
import { findInsertIndex, closest, reducer, DRAG_DATA} from "@bastet/utils";
import uuid from "uuid/v4";
import { widthResize } from "@bastet/widgets/src/components/controller";

interface IData {
  index?: number;
  contextPath?: string;
  data: IComponent
}
export interface IDroppableComponentProps {
  data: IBaseData;
  activated?: boolean;
  operate?: boolean;

  style?: CSSProperties;
  className?: string;
  onClick?: (ev: MouseEvent<Element>) => void;
  onDrop?: (ev: DragEvent<Element>, arg?: {  }) => void;
}

function findIndex (event: DragEvent <Element>, node: HTMLElement) {
  const childrenElement = node.childNodes
  const { x, y } = event.nativeEvent;
  const children: DOMRect[] = [];

  childrenElement?.forEach((item: any) => {
    const unableEvents = item.dataset?.unableEvents

    if (!unableEvents && item.nodeType !== 3) {
      children.push(item.getBoundingClientRect())
    }
  })

  return findInsertIndex(children, { x, y }, 'column')
}

/**
 * 接收拖拽目标组件
 * (event: MouseEvent<HTMLDivElement, MouseEvent>) => void
 */
export const DroppableComponent: FC<PropsWithChildren<IDroppableComponentProps>> = (
  {
    data,
    operate = true, // 是否可变换
    onClick,
    onDrop,
    children,
    style,
    className = '',
  },
) => {
  let handles: any[] = []
  /**
   * private: 私有
   * operate: 允许操作
   * position: relative(相对定位) | absolute(绝对定位) | fixed(固定定位) | sticky(粘性定位)
   *
   */
  if (!data.private && operate && ['relative', 'absolute', 'fixed', 'sticky'].includes(style?.position as string)) handles = [widthResize]
  const DroppableComp = reducer<FC<IDroppable>>(handles, Droppable, () => {
    console.log('path: => ', data.path)
  })

  const __onDrop = (event: DragEvent <Element>) => {
    event.preventDefault();
    const node: HTMLElement | undefined = closest(event.nativeEvent.target as HTMLElement, 'droppable');
    const transfer = event.dataTransfer.getData(DRAG_DATA);

    console.log('__onDrop', transfer)
    // removeSpace(event);
    if (!transfer || !node) return

    try {
      const dataTransfer: IComponent = JSON.parse(transfer);
      // 提交数据
      const data: IData = { contextPath: node.dataset.path, data: dataTransfer }
      if (!dataTransfer.id) dataTransfer.id = uuid()


      // removeSpace(event)
      const index = findIndex(event, node);
      data.index = index > 0 ? index : 0;
      console.log('__onDrop', dataTransfer, node, node.dataset.path, index)
      if (dataTransfer.path) {
        onDrop && onDrop(event, data)
      }
    } catch (error) {
      return console.log(error)
    } finally {
      // 清空拖拽的数据
      event.dataTransfer.clearData();
    }
  }

  console.log('DroppableComponent: => ', { data, operate, onClick, onDrop, children, style, className })
  return (
    <DroppableComp
      data={data}
      style={style}
      className={className}
      onDrop={(ev: DragEvent<Element>) => {
        ev.preventDefault();
        ev.stopPropagation();
        __onDrop(ev)
      }}
      onClick={onClick}
    >
      { children }
    </DroppableComp>
  )
}
